package com.vmj.heap;

import com.vmj.rtda.Slot;

/**
 * Created by yangshoujun on 2017/8/12 下午12:08.
 */
public class VMObject extends java.lang.Object implements Cloneable {

    private VMClass clazz;
    java.lang.Object data;
    java.lang.Object extra;

    public VMObject(VMClass clazz) {
        this.clazz = clazz;
        Slot[] slots = new Slot[clazz.getInstanceSlotCount()];
        Slots s = new Slots(slots);
        this.data = s;
    }

    public static VMObject newArray(VMClass clazz, int count) {
        if(!clazz.isArray()) {
            throw new RuntimeException("Not Array class: " + clazz.getName());
        }

        VMObject obj = null;
        String name = clazz.getName();
        if("[Z".equals(name)) {
            obj = new VMObject(clazz);
            obj.setData(new int[count]);
        } else if("[B".equals(name)) {
            obj = new VMObject(clazz);
            obj.setData(new byte[count]);
        } else if("[C".equals(name)) {
            obj = new VMObject(clazz);
            obj.setData(new char[count]);
        } else if("[S".equals(name)) {
            obj = new VMObject(clazz);
            obj.setData(new short[count]);
        } else if("[I".equals(name)) {
            obj = new VMObject(clazz);
            obj.setData(new int[count]);
        } else if("[J".equals(name)) {
            obj = new VMObject(clazz);
            obj.setData(new long[count]);
        } else if("[F".equals(name)) {
            obj = new VMObject(clazz);
            obj.setData(new float[count]);
        } else if("[D".equals(name)) {
            obj = new VMObject(clazz);
            obj.setData(new double[count]);
        } else {
            obj = new VMObject(clazz);
            obj.setData(new VMObject[count]);
        }

        return obj;
    }

    public void setRefVar(String name, String descriptor, VMObject ref) {
        Field field = clazz.getField(name, descriptor, false);
        Slots slots = (Slots) getData();
        slots.setRef(field.getSlotId(), ref);
    }

    public void setIntVar(String name, int value) {
        Field field = clazz.getField(name, "I", false);
        Slots slots = (Slots) getData();
        slots.setInt(field.getSlotId(), value);
    }

    public VMObject getRefVar(String name, String descriptor) {
        Field field = clazz.getField(name, descriptor, false);
        Slots slots = (Slots) data;
        return slots.getRef(field.getSlotId());
    }

    public int getIntVar(String name, String descriptor) {
        Field field = clazz.getField(name, descriptor, false);
        Slots slots = (Slots) data;
        return slots.getInt(field.getSlotId());
    }

    public String getRefString() {
        Field field = clazz.getField("value", "[C", false);
        Slots slots = (Slots) data;
        VMObject obj = slots.getRef(field.getSlotId());
        char[] data = (char[]) obj.getData();
        return new String(data);
    }

    public java.lang.Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    public boolean isInstanceOf(VMClass clazz) {
        return clazz.isAssignableFrom(this.clazz);
    }

    public Slots getFields() {
        return (Slots) this.data;
    }

    public VMClass getClazz() {
        return clazz;
    }

    public void setClazz(VMClass clazz) {
        this.clazz = clazz;
    }

    public java.lang.Object getData() {
        return data;
    }

    public void setData(java.lang.Object data) {
        this.data = data;
    }

    public java.lang.Object getExtra() {
        return extra;
    }

    public void setExtra(java.lang.Object extra) {
        this.extra = extra;
    }

    @Override
    public String toString() {
        return "Object{" +
                "clazz=" + clazz +
                ", data=" + data +
                ", extra=" + extra +
                '}';
    }
}
